package com.xuantian.baoming.utils;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Formatter;

/**
 * 加解密工具类
 * <p>
 *     常用加密解密算法的工具类
 * </p>
 * @author feizns
 */
public class EncryptUtils {

    /**
     * 默认编码
     */
    private static final String DEFAULT_CHARSET = "UTF-8";

    /**
     * 16进制字符
     */
    private static final char[] hexDigits = "0123456789ABCDEF".toCharArray();

    /**
     * SHA1加密
     * @param str {@link String}
     * @return 返回加密后的字符
     */
    public static String sha1(String str) {
        return update(str, "SHA1");
    }

    /**
     * SHA-256加密
     * @param str {@link String}
     * @return 加密后的字符
     */
    public static String sha256(String str) {
        return update(str, "SHA-256");
    }

    /**
     * SHA-512加密
     * @param str {@link String}
     * @return 加密后的字符
     */
    public static String sha512(String str) {
        return update(str, "SHA-512");
    }

    /**
     * md5加密
     * @param str {@link String}
     * @return 加密字符
     */
    public static String md5(String str) {
        return update(str, "MD5");
    }

    /**
     * 对普通字符进行base64编码
     * @param str {@link String}
     * @return 编码后的字符
     */
    public static String base64Encode(String str) {
        return new String(base64Encode(str.getBytes()));
    }

    /**
     * 对普通字符进行base64编码
     * @param bytes 字节数据
     * @return 编码后的字符
     */
    public static byte[] base64Encode(byte[] bytes) {
        return Base64.getEncoder().encode(bytes);
    }

    /**
     * 对base64字符str进行解码
     * @param str {@link String}
     * @return 解码后的字符
     */
    public static String base64Decode(String str) {
        return new String(base64Decode(str.getBytes()));
    }

    /**
     * 对base64字符str进行解码
     * @param bytes {@link Byte}
     * @return 解码后的字符
     */
    public static byte[] base64Decode(byte[] bytes) {
        return Base64.getDecoder().decode(bytes);
    }

    /**
     * 指定对于字符的加密算法并做加密转换
     * @see #update(byte[], String)
     * @param str {@link String}
     * @param algorithm 算法
     * @return 加密后的字符
     */
    private static String update(String str, String algorithm) {
        try {
            return update(str.getBytes(DEFAULT_CHARSET), algorithm);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 指定对于字符的加密算法并做加密转换
     * @param bytes {@link Byte}
     * @param algorithm 算法
     * @return 加密后的字符
     */
    private static String update(byte[] bytes, String algorithm) {
        try {
            MessageDigest mdTemp = MessageDigest.getInstance(algorithm);
            mdTemp.update(bytes);

            byte[] md = mdTemp.digest();
            int j = md.length;
            char[] buf = new char[j * 2];
            int k = 0;
            for (byte byte0 : md) {
                buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
                buf[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(buf);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * <a href="https://blog.csdn.net/liaoxiaoyi121121/article/details/80408479">Java生成MD5的坑</a>
     * @param bytes 字节
     * @return 16进制字符
     */
    private static String toHexString(byte[] bytes) {
        try ( Formatter formatter = new Formatter() ) {
            for (byte b : bytes) {
                formatter.format("%02x", b);
            }
            return formatter.toString();
        }
    }

}
